using System; 
using System.Collections.Generic;
using UnityEngine;

namespace XFFSM
{
    [Serializable]
    public class RuntimeFSMControllerLayer 
    {
        /// <summary>
        /// 状态机层的名称
        /// </summary>
        public string name;
        /// <summary>
        /// 状态配置文件
        /// </summary>
        public RuntimeFSMController controller;
    }

    public class FSMController : MonoBehaviour
    {

        #region 字段

        [SerializeField] 
        private List<RuntimeFSMController> _runtimeFSMController = new List<RuntimeFSMController>();

        [SerializeField]
        private List<RuntimeFSMControllerLayer> _runtimeFSMControllerLayer = new List<RuntimeFSMControllerLayer>();

        internal object userData;

        private List<RuntimeFSMControllerInstance> Instances = new List<RuntimeFSMControllerInstance>();
        
        private List<RuntimeFSMController> runtimeControllers = new List<RuntimeFSMController>();

        private List<RuntimeFSMControllerLayer> runtimeFSMControllerLayer = new List<RuntimeFSMControllerLayer>();

        [SerializeField]
        [Tooltip("是否在OnDisable时重置状态机")]
        [Header("是否在OnDisable时重置状态机")]
        private bool resetOnDisable = true;
        
        #endregion

        #region 事件
        /// <summary>
        /// 初始化完成的回调
        /// </summary>
        public Action onInitFinish;
        /// <summary>
        /// 状态改变的回调 参数1:状态机名称 参数2:当前状态 
        /// </summary>
        public Action<string,string> onStateChange;

        #endregion

        #region 属性

        /// <summary>
        /// 当前状态机执行的状态配置文件列表
        /// </summary> 
        public List<RuntimeFSMController> RuntimeFSMController
        {
            get
            {
                runtimeControllers.Clear();

                if (Application.isPlaying)
                {
                    foreach (var item in runtimeFSMControllerLayer)
                    {
                        if (item.controller == null) continue;
                        runtimeControllers.Add(item.controller);
                    }
                }
                else {
                    foreach (var item in _runtimeFSMControllerLayer)
                    {
                        if (item.controller == null) continue;
                        runtimeControllers.Add(item.controller);
                    }
                }

                return runtimeControllers;
            } 
        }

        public List<RuntimeFSMControllerLayer> RuntimeFSMControllerLayers 
        {
            get 
            {
                if (Application.isPlaying)
                { 
                    return runtimeFSMControllerLayer;
                }
                
                return _runtimeFSMControllerLayer;
            }
        }

        /// <summary>
        /// 状态机是否初始化完成
        /// </summary>
        public bool Initialized { get; private set; } = false;

        #endregion

        #region 生命周期

        private void Start()
        {
            Init();
        }
        
        private void Update()
        {  
            foreach (var item in Instances)
            {
                // 如果没有启动 就启动一下
                if(!item.Started) 
                    item.StartUp();
                
                item.Update();
            }
        }

        private void LateUpdate()
        { 
            foreach (var item in Instances)
            {
                item.LateUpdate();
            }
        }

        private void FixedUpdate()
        { 
            foreach (var item in Instances)
            {
                item.FixedUpdate();
            }
        }
         
        private void OnDestroy() 
        {
            foreach (var item in Instances)
            {
                item.Close();
            }
        }

        private void OnDisable()
        {
            if (resetOnDisable)
            {
                foreach (var item in Instances)
                {
                    item.Close();
                }
            }
        }

        #endregion

        #region 方法

        // 初始化
        private void Init()
        {
            Instances.Clear();
            //runtimeControllers.Clear();

            //foreach (var item in _runtimeFSMController) 
            //{
            //    if (item == null) continue;

            //    RuntimeFSMControllerInstance instance = new RuntimeFSMControllerInstance(item, this);
            //    instance.StartUp();
            //    runtimeControllers.Add(instance.RuntimeFSMController);
            //    Instances.Add(instance);
            //}
              
            // 兼容
            if (_runtimeFSMControllerLayer.Count == 0 && _runtimeFSMController.Count > 0) 
            {
                for (int i = 0; i < _runtimeFSMController.Count; i++) 
                {
                    if(_runtimeFSMController[i] == null) continue; 
                    RuntimeFSMControllerLayer layer = new RuntimeFSMControllerLayer(); 
                    layer.name = string.Format("Layer {0}",i);
                    layer.controller = _runtimeFSMController[i];
                    _runtimeFSMControllerLayer.Add(layer);
                } 
            }

            runtimeFSMControllerLayer.Clear();

            foreach (var item in _runtimeFSMControllerLayer)
            {
                if(item.controller == null) continue;
                RuntimeFSMControllerInstance instance = new RuntimeFSMControllerInstance(item.controller, this,item.name);
                instance.StartUp();

                RuntimeFSMControllerLayer layer = new RuntimeFSMControllerLayer();
                layer.name = item.name;
                layer.controller = instance.RuntimeFSMController;
                runtimeFSMControllerLayer.Add(layer);
                Instances.Add(instance);
            }
             
            Initialized = true;
            onInitFinish?.Invoke();
        }

        public void SetBool(string name, bool v) 
        {
            SetBool(StringToHash(name), v);
        }

        /// <summary>
        /// 设置bool类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <param name="v">值</param>
        public void SetBool(int name_hash, bool v)
        {
            if (Initialized)
            {
                if (!IsContainParameter(name_hash, ParameterType.Bool))
                {
                    Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}",HashToString( name_hash), ParameterType.Bool);
                    return;
                }

                foreach (var item in Instances)
                {
                    item.SetBool(name_hash, v);
                }
            }
            else 
            {
                onInitFinish += () => 
                {
                    if (!IsContainParameter(name_hash, ParameterType.Bool))
                    {
                        Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString( name_hash), ParameterType.Bool);
                        return;
                    }

                    foreach (var item in Instances)
                    {
                        item.SetBool(name_hash, v);
                    }
                };
            }
        }

        public void SetFloat(string name, float v) 
        {
            SetFloat(StringToHash(name), v);
        }

        /// <summary>
        /// 设置float类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <param name="v">值</param>
        public void SetFloat(int name_hash, float v)
        {
            if (Initialized)
            {
                if (!IsContainParameter(name_hash, ParameterType.Float))
                {
                    Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString(name_hash), ParameterType.Float);
                    return;
                }

                foreach (var item in Instances)
                {
                    item.SetFloat(name_hash, v);
                }
            }
            else {
                onInitFinish += () =>
                {
                    if (!IsContainParameter(name_hash, ParameterType.Float))
                    {
                        Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString(name_hash), ParameterType.Float);
                        return;
                    }

                    foreach (var item in Instances)
                    {
                        item.SetFloat(name_hash, v);
                    }
                };
            }

        }

        public void SetInt(string name, int v)
        {
            SetInt(StringToHash(name), v);
        }

        /// <summary>
        /// 设置Int类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <param name="v">值</param>
        public void SetInt(int name_hash, int v)
        {
            if (Initialized)
            {
                if (!IsContainParameter(name_hash, ParameterType.Int))
                {
                    Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString(name_hash), ParameterType.Int);
                    return;
                }

                foreach (var item in Instances)
                {
                    item.SetInt(name_hash, v);
                }
            }
            else {
                onInitFinish += () => 
                {
                    if (!IsContainParameter(name_hash, ParameterType.Int))
                    {
                        Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString(name_hash), ParameterType.Int);
                        return;
                    }

                    foreach (var item in Instances)
                    {
                        item.SetInt(name_hash, v);
                    }
                };
            }

        }

        public void SetTrigger(string name) 
        {
            SetTrigger(StringToHash(name));
        }

        /// <summary>
        /// 触发Trigger
        /// </summary>
        /// <param name="name_hash">Trigger名称</param>
        public void SetTrigger(int name_hash) 
        {
            if (Initialized)
            {
                if (!IsContainParameter(name_hash, ParameterType.Trigger))
                {
                    Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString( name_hash), ParameterType.Trigger);
                    return;
                }

                foreach (var item in Instances)
                {
                    
                    item.SetTrigger(name_hash);
                }
            }
            else 
            {
                onInitFinish += () =>
                {
                    if (!IsContainParameter(name_hash, ParameterType.Trigger))
                    {
                        Debug.LogWarningFormat("未查询到参数:{0} 类型:{1}", HashToString( name_hash), ParameterType.Trigger);
                        return;
                    }

                    foreach (var item in Instances)
                    {
                        item.SetTrigger(name_hash);
                    }
                };
            }

        }

        public void ResetTrigger(string name)
        {
            ResetTrigger(StringToHash(name));
        }

        /// <summary>
        /// 还原Trigger
        /// </summary>
        /// <param name="name_hash">Trigger名称</param>
        public void ResetTrigger(int name_hash) 
        {
            foreach (var item in Instances)
            {
                item.ResetTrigger(name_hash);
            }
        }

        public bool GetBool(string name) 
        {
            return GetBool(StringToHash(name));
        }

        /// <summary>
        /// 获取Bool类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <returns></returns>
        public bool GetBool(int name_hash) 
        { 
            foreach (var item in Instances)
            {
                if (item.GetParamter(name_hash) == 1)
                    return true;
            }
             
            return false;
        }

        public float GetFloat(string name) 
        {
            return GetFloat(StringToHash(name));
        }

        /// <summary>
        /// 获取Float类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <returns></returns>
        public float GetFloat(int name_hash )
        {
            foreach (var item in Instances)
            {
                float v = item.GetParamter(name_hash);
                if (v != 0)
                    return v;
            }

            return 0;
        }

        public int GetInt(string name) 
        {
            return GetInt(StringToHash(name));
        }

        /// <summary>
        /// 获取Int类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <returns></returns>
        public int GetInt(int name_hash)
        {
            foreach (var item in Instances)
            {
                int v = (int)(item.GetParamter(name_hash));
                if (v != 0)
                    return v;
            }
            
            return 0;
        }

        public bool GetTrigger(string name) {
            return GetTrigger(StringToHash(name));
        }

        /// <summary>
        /// 获取Trigger类型参数的值
        /// </summary>
        /// <param name="name_hash">参数名称</param>
        /// <returns></returns>
        public bool GetTrigger(int name_hash ) 
        {
            foreach (var item in Instances)
            {
                if (item.GetTriggerCount(name_hash) > 0 || item.GetParamter(name_hash) == 1)
                    return true; 
            } 
            return false;
        }

        private bool IsContainParameter(int name,ParameterType type) 
        {
            foreach (var item in Instances)
            {
                if(item.parameters.ContainsKey(name) && item.parameters[name].parameterType == type)
                    return true;
            }

            return false;
        }


        /// <summary>
        /// 运行时添加并执行状态配置文件
        /// </summary>
        /// <param name="controller"></param>
        public void AddRuntimeFSMController(RuntimeFSMController controller)
        {
            string layerName = string.Format("Layer:{0}", controller.GetHashCode());
            AddRuntimeFSMController(controller, layerName);
        }
         
        /// <summary>
        /// 运行时添加并执行状态配置文件
        /// </summary>
        /// <param name="controller"></param>
        public void AddRuntimeFSMController(RuntimeFSMController controller,string layerName)
        {
            if (controller == null) return;
             
            if (Contains(_runtimeFSMControllerLayer, controller))
            {
                Debug.LogWarningFormat("状态机:{0}已经执行,请勿重复添加!", controller.name);
                return; // 说明已经添加了该状态机
            }
              
            RuntimeFSMControllerLayer layer = new RuntimeFSMControllerLayer();
            layer.name = layerName;
            layer.controller = controller; 
            _runtimeFSMControllerLayer.Add(layer);
             

            // 如果没有初始化完成 不需要处理 在初始化的时候会处理
            if (Initialized) 
            {
                // 如果初始化完成了 启动这个状态
                RuntimeFSMControllerInstance controllerInstance = new RuntimeFSMControllerInstance(controller, this, layerName);
                controllerInstance.StartUp();

                RuntimeFSMControllerLayer layer2 = new RuntimeFSMControllerLayer();
                layer2.name = layerName;
                layer2.controller = controllerInstance.RuntimeFSMController; 
                runtimeFSMControllerLayer.Add(layer2); 

                Instances.Add(controllerInstance);
            }

        }

        public void RemoveRuntimeFSMController(string layerName)
        {
            if (string.IsNullOrEmpty(layerName)) 
                return;

            int index = -1;

            for (int i = 0; i < RuntimeFSMControllerLayers.Count; i++) 
            {
                if (layerName == RuntimeFSMControllerLayers[i].name) 
                {
                    index = i;
                    break;
                }
            }

            if(index != -1)
                RemoveRuntimeFSMController(index); 
        }


        /// <summary>
        /// 运行时移除状态机配置文件
        /// </summary>
        /// <param name="index">配置文件下标</param>
        public void RemoveRuntimeFSMController(int index) 
        {
            if (index < 0 || index >= RuntimeFSMControllerLayers.Count) return;
            RuntimeFSMControllerLayer controller = RuntimeFSMControllerLayers[index];
            RuntimeFSMControllerLayers.RemoveAt(index);

            for (int i = 0; i < Instances.Count; i++)
            {
                if (Instances[i].RuntimeFSMController == controller.controller) 
                {
                    Instances[i].Close();
                    Instances.Remove(Instances[i]);
                    break;
                }
            }
        }

        /// <summary>
        /// 获取当前正在执行的状态信息
        /// </summary>
        /// <param name="index">状态配置下标</param>
        /// <param name="subStateName">子状态机名称(默认:空)</param>
        /// <returns></returns>
        public FSMStateNode GetCurrentStateInfo(int index,string subStateName = "")
        {
            if (index < 0 || index >= Instances.Count) return null;
            return Instances[index].GetCurrentState(subStateName);
        }

        public FSMStateNode GetCurrentStateInfo(string layerName, string subStateName = "") {

            if (string.IsNullOrEmpty(layerName))
                return null;

            foreach (var item in Instances)
            {
                if (item.layerName.Equals(layerName))
                    return item.GetCurrentState(subStateName);
            }

            return null;
        }

        /// <summary>
        /// 获取当前的状态切换信息
        /// </summary>
        /// <param name="controller"></param>
        /// <returns></returns>
        public FSMTransition GetCurrentTransition(int index) 
        {
            if (index < 0 || index >= Instances.Count) return null;
            return Instances[index].currentTransition; 
        }


        private bool Contains(List<RuntimeFSMControllerLayer> layers,RuntimeFSMController controller) 
        {
            if(controller == null) return false;

            foreach (var layer in layers) 
            {
                if(layer == null) continue;
                if (layer.controller == controller) return true;
            }
            return false;
        }
         
        #endregion

        #region 静态字段

        private static Dictionary<string,FSMController> fsms = new Dictionary<string,FSMController>();

        #endregion

        #region 静态属性
         

        private static Transform FSMParent { get; set; }

        #endregion

        #region 静态方法


        [RuntimeInitializeOnLoadMethod]
        static void InitFSMController()
        {
            fsms.Clear();

            GameObject obj = new GameObject("FSMControllers");
            DontDestroyOnLoad(obj);
            FSMParent = obj.transform;
        }

        /// <summary>
        /// 启动状态(适用于没有具体游戏物体的状态管理,例如:游戏状态)
        /// </summary>
        /// <param name="fsmName">状态机名称</param>
        /// <param name="fsm">状态配置文件</param>
        /// <param name="userData">自定义参数或数据</param>
        /// <returns></returns>
        public static FSMController StartupFSM(string fsmName,RuntimeFSMController fsm,object userData = null)
        {
            if (fsms.ContainsKey(fsmName)) return null;
            GameObject obj = new GameObject(fsmName);
            obj.transform.SetParent(FSMParent,false);
            FSMController controller = obj.AddComponent<FSMController>();
            controller.userData = userData;
            controller.AddRuntimeFSMController(fsm);
            fsms.Add(fsmName, controller);
            return controller;
        }

        /// <summary>
        /// 查询通过FSMController.StartupFSM启动的状态机
        /// </summary>
        /// <param name="fsmName">状态机名称</param>
        /// <returns></returns>
        public static FSMController GetFSM(string fsmName)
        {
            if(fsms.ContainsKey(fsmName)) 
                return fsms[fsmName];
            return null;
        }

        /// <summary>
        /// 移除通过FSMController.StartupFSM启动的状态机
        /// </summary>
        /// <param name="fsmName">状态机名称</param>
        public static void RemoveFSM(string fsmName)
        {
            if (!fsms.ContainsKey(fsmName)) return;
            FSMController controller = fsms[fsmName];
            fsms.Remove(fsmName);
            Destroy(controller.gameObject);
        }

        #endregion


        #region StringToHash

        private static Dictionary<string, int> string_hashs = new Dictionary<string, int>();
        private static Dictionary<int, string> hash_strings = new Dictionary<int, string>();


        public static int StringToHash(string event_name)
        {
            if (string_hashs.ContainsKey(event_name))
                return string_hashs[event_name];

            int hash = Animator.StringToHash(event_name);

            string_hashs.Add(event_name, hash);
            if (!hash_strings.ContainsKey(hash))
                hash_strings.Add(hash, event_name);

            return string_hashs[event_name];
        }

        internal static string HashToString(int hash)
        {
            if (hash_strings.ContainsKey(hash))
                return hash_strings[hash];

            return string.Empty;
        }

        #endregion


    }

}

